package tomasulogui;

public class ReservationStation {
  PipelineSimulator simulator;

  int tag1;
  int tag2;
  int data1;
  int data2;
  int immediate;
  boolean data1Valid = false;
  boolean data2Valid = false;
  // destTag doubles as branch tag
  int destTag;
  IssuedInst.INST_TYPE function = IssuedInst.INST_TYPE.NOP;

  // following just for branches
  int addressTag;
  boolean addressValid = false;
  int address;
  boolean predictedTaken = false;
  boolean isBranch = false;
  
  int pc;

  public ReservationStation(PipelineSimulator sim) {
    simulator = sim;
  }

  public int getDestTag() {
    return destTag;
  }

  public int getData1() {
    return data1;
  }

  public int getData2() {
    return data2;
  }

  public boolean isPredictedTaken() {
    return predictedTaken;
  }

  public IssuedInst.INST_TYPE getFunction() {
    return function;
  }

  public void snoop(CDB cdb) {
    // TODO - add code to snoop on CDB each cycle
      if(cdb.getDataTag() == tag1){
          data1 = cdb.getDataValue();
          data1Valid = true;
      }
      if(cdb.getDataTag() == tag2){
          data2 = cdb.getDataValue();
          data2Valid = true;
      }
      if(cdb.getDataTag() == addressTag){
          address = cdb.getDataValue() + pc;
          addressValid = true;
      }
  }

  public boolean isReady() {
    return data1Valid && data2Valid;
  }

  public void loadInst(IssuedInst inst) {
      // get the values from the instruction to set the values in the station
      pc = inst.getPC();
      tag1 = inst.regSrc1Tag;
      tag2 = inst.regSrc2Tag;
      if(inst.regSrc1Used){
        data1 = inst.regSrc1Value;
        data1Valid = inst.regSrc1Valid;
      }
      else{
          data1Valid = true;
      }
      if(inst.regSrc2Used){
        data2 = inst.regSrc2Value;
        data2Valid = inst.regSrc2Valid;
      }
      else{
          data2 = inst.getImmediate();
          data2Valid = true;
      }
      immediate = inst.immediate;
      
      if(inst.regDestUsed){
          // the rearQ has already been incremented, so we must decrement it for the value we need.
          destTag = simulator.getROB().getRearQMinusOne();
      }
      else{
        destTag = inst.regDestTag;        // This may have to be used for something with branches
      }
      function = inst.opcode;
      
      if(inst.determineIfBranch()){
          addressTag = inst.regSrc1Tag;
          addressValid = inst.regSrc1Valid;
          address = inst.branchTgt;
          predictedTaken = inst.branchPrediction;
          isBranch = true;
      }
  }
}
